#include "Sock.hpp"
#include <iostream>
#include <poll.h>
#define NUM 128
struct pollfd fd_array[NUM]; // fd > 0 合法fd, 若fd < 0 则表示该位置没有fd

static void Usage(std::string proc)
{
    std::cout << "Usage: \n\t" << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    uint16_t port = (uint16_t)atoi(argv[1]);
    int listen_sock = Sock::Socket();
    Sock::Bind(listen_sock, port);
    Sock::Listen(listen_sock);

    for (int i = 0; i < NUM; i++)
    {
        fd_array[i].fd = -1;
        fd_array[i].events = 0;
        fd_array[i].revents = 0;
    }

    fd_array[0].fd = listen_sock;
    fd_array[0].events = POLLIN;
    
    // accept: 不应该，accept的本质叫做通过listen_sock获取新连接
    //         前提是listen_sock上面有新连接，accept怎么直到有新连接呢？？
    //         不知道！！！accept阻塞式等待

    // 站在多路转接的视角，我们认为链接到来，对于listen_sock,就是读事件就绪
    // 对于所有的服务器，最开始的时候只有listen_sock

    // 事件循环
    for (;;)
    {
        int n = poll(fd_array, NUM, 1000);
        switch (n)
        {
        case -1:
            std::cerr << "select error" << std::endl;
            break;
        case 0:
            std::cout << "select timeout" << std::endl;
            break;
        default:
            std::cout << "有fd对应的事件就绪了" << std::endl;
            for (int i = 0; i < NUM; i++)
            {
                if (fd_array[i].fd == -1)
                    continue;
                if (FD_ISSET(fd_array[i], &rfds))
                {
                    // 读事件就绪了！！ 就绪的fd就在fd_array[i]中保存
                    // 此时调用read, recv, accept等接口一定不会被阻塞
                    std::cout << "sock: " << fd_array[i] << " 上面有了读事件，可以读取了" << std::endl;
                    if (fd_array[i] == listen_sock)
                    {
                        // listen_sock 读就绪，调用accept
                        std::cout << "listen_sock: " << listen_sock << " 有了新的连接到来" << std::endl;
                        int sock = Sock::Accept(listen_sock);
                        if (sock >= 0)
                        {
                            std::cout << "listen_sock: " << listen_sock << " 获取新的连接成功" << std::endl;
                            // 获取链接成功，不能直接进行recv或者read，若被恶意链接，对方不发送信息，我们的服务器就会被挂起
                            // 所以新连接到来，并不意味着数据到来！！只有select直到那些fd上的信息可以被读取了，可以将其放入fd_array
                            int pos = 1;
                            for (; pos < NUM; pos++)
                            {
                                if (fd_array[pos] == -1)
                                    break;
                            }
                            // 1.找到一个位置没有被使用
                            if (pos < NUM)
                            {
                                fd_array[pos] = sock;
                                std::cout << "新连接: " << sock << " 已经被添加到了数组[" << pos << "]的位置" << std::endl;
                            }
                            // 2.所有位置全部被占用了，服务器已经满载，没法处理新的请求了
                            else
                            {
                                close(sock);
                                std::cout << "服务器已经满载了，关闭新的连接" << std::endl;
                            }
                        }
                    }
                    else
                    {
                        // 普通的sock，读事件就绪了，可以进行读取了
                        // 可是，数据已经完全准备好了吗？？有没有可能数据只发了一半呢？？就没有所谓的数据包粘包问题吗？？
                        // 今天我们没有场景不能解决，没有场景就无法定制协议。
                        std::cout << "sock: " << fd_array[i] << " 上面有普通读取" << std::endl;
                        char recv_buffer[1024] = {0};
                        ssize_t s = recv(fd_array[i], recv_buffer, sizeof(recv_buffer) - 1, 0);
                        if (s > 0)
                        { // 读取成功
                            recv_buffer[s] = 0;
                            std::cout << "client[" << fd_array[i] << "]# " << recv_buffer << std::endl;
                        }
                        else if (s == 0)
                        { // 对端关闭连接
                            std::cout << "sock:" << fd_array[i] << "客户端推出了" << std::endl;
                            close(fd_array[i]);
                            std::cout << "已经在数组fd_array[" << i << "]中,去掉了sock: " << fd_array[i];
                            fd_array[i] = -1;
                        }
                        else
                        { // 读取失败
                            std::cerr << "recv errno" << errno << std::endl;
                        }
                    }
                }
            }
            break;
        }
    }
    return 0;
}